package com.aos;

public class Receiver extends Thread
{
	public String msg;
	
	public Receiver(String msg)
	{
		this.msg = msg;
	}
	public void run()
	{
		while(!Node.isNodeUp()) //checking whether node is up---need to consider while later
		{
			
		}
		// a message has been received
		String[] rMessage = msg.split("~");
		int senderNode = Integer.parseInt(rMessage[1]);
		
		//System.out.println(rMessage[0] + "::" + Node.nodeInfo.getID() + "<--" + senderNode);
		
		if(rMessage[0].equals(Communication.m_msg))
		{ // receive hello message or M message
			if(Node.parent == -1)
			{  // node parent is empty
				Node.parent = senderNode; // set node parent
				//System.out.println("Parent: " + Node.parent);
				for(Integer neighbor : Node.neighbors.keySet())
				{
					if(neighbor != Node.parent){ // if not parent send M message to neighbor
						Communication.sendMessage(Client.senderList.get(neighbor), Communication.m_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(neighbor));
					}
					else // send parent message to 'parent' node
					{
						Communication.sendMessage(Client.senderList.get(neighbor), Communication.p_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(neighbor));
						
						//checking termination for leaf
						if(Node.children.size() + Node.others.size() + 1 == Node.neighbors.size())
						{
							Node.terminateSpanningProcess();
							//System.out.println("Node Terminated: " + Node.isSpanningCompleted());
							//System.out.println("***Time to terminate***");
						}
					}
				}
			}
			else
			{ // parent is set, so send an 'already' message to   
				Communication.sendMessage(Client.senderList.get(senderNode), Communication.a_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(senderNode));
			}
		}
		
		int parentOffset = Node.nodeInfo.getID() == Node.parent ? 0 : 1; //checking whether this is designated node
		
		// receive a parent message
		if(rMessage[0].equals(Communication.p_msg))
		{
			//System.out.println("Parent Msg Received.");
			Node.children.add(senderNode); // add sender Node as a child Node
			Node.incChildCount();
			if((Node.children.size()+Node.others.size()) == (Node.neighbors.size() - parentOffset)){ // termination condition
				//System.out.println("^^^Time to terminate^^^");
				Node.terminateSpanningProcess();
			}
		}
		
		if(rMessage[0].equals(Communication.a_msg)){ // receive an already message
			//System.out.println("Already Msg Received.");
			Node.others.add(senderNode); // add sender Node as a child Node
			
			if((Node.children.size()+Node.others.size()) == (Node.neighbors.size() - parentOffset)){  // termination condition
				//System.out.println("@@@Time to terminate@@@");
				Node.terminateSpanningProcess();
			}
		}
		
		if(rMessage[0].equals(Communication.t_msg))
		{
			Node.tokenReqQueue.add(senderNode);	//adding the sender node to the request queue
			
			Node.updateSpanTreeInfo(Integer.parseInt(rMessage[2]), Integer.parseInt(rMessage[3]), rMessage[4], rMessage[5]);
			Node.incTMsgCount();
			
		}
		
		if(rMessage[0].equals(Communication.h_req_msg))
		{
			if(Node.children.size() == 0)	//for leaf node
			{
				String msg = Node.nodeInfo.getID() + "~" + Integer.toString(Node.maxHeight + 1);
				//System.out.println("Parent:::::::::"+Node.parent);
				Node.resetMaxHeight();
				Communication.sendMessage(Client.senderList.get(Node.parent), Communication.h_rpl_msg, msg, Integer.toString(Node.parent));
			}
			for(Integer child : Node.children)
			{
				Communication.sendMessage(Client.senderList.get(child), Communication.h_req_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(child));
			}
		}
		
		if(rMessage[0].equals(Communication.h_rpl_msg))
		{
			Node.updateMaxHeight(Integer.parseInt(rMessage[2]));
			Node.incHRplMsgCount();
			if(Node.hasReceivedAllHRplMsg())
			{
				//System.out.println("All H message received.");
				if(Node.nodeInfo.getID() == Node.parent)
				{
					int height = Node.maxHeight + 1;	//adding 1 for current node
					Node.resetMaxHeight();
					Node.heightInfo += "," + Node.nodeInfo.getID() + " " + height;
					Node.isHeightComputed = true;
					Node.tokenReqQueue.remove();
					
					int nextNode = Node.tokenReqQueue.remove();
					//System.out.println("NextNode: "+ nextNode);
					//System.out.println("Child List" + Node.children.toString());
					Node.parent = nextNode;
					Node.children.remove(new Integer(nextNode));
					
					//System.out.println("Child List" + Node.children.toString());
					//if the node request queue is empty but not the designated node
					if((Node.tokenReqQueue.size() == 0) & (Node.nodeInfo.getID() != Node.dNode))
					{						
						String msg = Node.nodeInfo.getID() + "~" + Node.heightInfo;
						Communication.sendMessage(Client.senderList.get(nextNode), Communication.priv_rpl_msg, msg, Integer.toString(nextNode));
					}else	//for every other condition including designated node
					{
						Communication.sendMessage(Client.senderList.get(nextNode), Communication.priv_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(nextNode));					
					}
					
					//System.out.println("Tree Height rooted at "+Node.nodeInfo.getID() + "::" + height);
				}else
				{
					String msg = Node.nodeInfo.getID() + "~" + Integer.toString(Node.maxHeight + 1);
					Node.resetMaxHeight();
					Communication.sendMessage(Client.senderList.get(Node.parent), Communication.h_rpl_msg, msg, Integer.toString(Node.parent));				
				}
			}
		}
		
		if(rMessage[0].equals(Communication.priv_msg))
		{
			Node.tokenReqQueue.add(senderNode);	//adding the sender node in the queue to track the parent
			Node.children.add(senderNode);
			Node.parent = Node.nodeInfo.getID();
			
			//start height computation process
			for(Integer child : Node.children)
			{
				Communication.sendMessage(Client.senderList.get(child), Communication.h_req_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(child));
			}
		}
		
		if(rMessage[0].equals(Communication.priv_rpl_msg))
		{
			Node.children.add(senderNode);
			Node.heightInfo += "," + rMessage[2];
			//designated node has received all the privilege reply from children
			if((Node.nodeInfo.getID() == Node.dNode) & (Node.tokenReqQueue.size() == 0))
			{
				//System.out.println(Node.heightInfo);
				Node.printOutputFile();
				return;
			}
			
			int nextNode = Node.tokenReqQueue.remove();
			//System.out.println("Next Priv Rpl" + nextNode);
			//If a non designated node request queue is empty then pass the privilege reply upward
			if((Node.tokenReqQueue.size() == 0) & (Node.nodeInfo.getID() != Node.dNode))
			{
					Node.parent = nextNode;
					Node.children.remove(new Integer(nextNode));
					String msg = Node.nodeInfo.getID() + "~" + Node.heightInfo;
					Communication.sendMessage(Client.senderList.get(nextNode), Communication.priv_rpl_msg, msg, Integer.toString(nextNode));							
			}else
			{
				Node.parent = nextNode;
				Node.children.remove(new Integer(nextNode));
				Communication.sendMessage(Client.senderList.get(nextNode), Communication.priv_msg, Integer.toString(Node.nodeInfo.getID()), Integer.toString(nextNode));
			}
		}
	}
}
